package pl.umk.mat.fred.unicore.urc.storagemanagement.actions;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.codehaus.xfire.service.binding.MessageBinding;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.ui.PlatformUI;
import org.omg.CosNaming.IstringHelper;
import org.unigrids.x2006.x04.services.sms.PermissionsChangeModeType;
import org.unigrids.x2006.x04.services.sms.PermissionsChangeModeType.Enum;
import org.unigrids.x2006.x04.services.sms.PermissionsClassType;

import de.fzj.unicore.wsrflite.xmlbeans.BaseFault;

import pl.umk.mat.fred.unicore.urc.storagemanagement.dialogs.ChangePermissions2Dialog;
import pl.umk.mat.fred.unicore.urc.storagemanagement.dialogs.ChangePermissionsDialog;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.LabelProviderImplementation;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.BelowStorageNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.BelowStorageNode.NewPermissions;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.BelowStorageNode.OldPermissions;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.CatalogNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.utils.TreeUtils;
import pl.umk.mat.fred.unicore.urc.storagemanagement.views.StorageBrowserView;

public class ChangePermissionsAction extends Action {

	private class DialogHelper {
		private int returnCode;
		private Enum mode;
		private Boolean recursively;  
		
		private Boolean changed;
		private Boolean userPermissionsChanged;
		private Boolean groupPermissionsChanged;
		private Boolean otherPermissionsChanged;
		
		private Boolean r;
		private Boolean w;
		private Boolean x;
		
		private String userPermissions;
		private String groupPermissions;
		private String otherPermissions;

		public Boolean getChanged() {
    	return changed;
    }
		public void setChanged(Boolean changed) {
    	this.changed = changed;
    }
		public Boolean getR() {
    	return r;
    }
		public void setR(Boolean r) {
    	this.r = r;
    }
		public Boolean getW() {
    	return w;
    }
		public void setW(Boolean w) {
    	this.w = w;
    }
		public Boolean getX() {
    	return x;
    }
		public void setX(Boolean x) {
    	this.x = x;
    }
		public int getReturnCode() {
    	return returnCode;
    }
		public void setReturnCode(int returnCode) {
    	this.returnCode = returnCode;
    }
		public Enum getMode() {
    	return mode;
    }
		public void setMode(Enum mode) {
    	this.mode = mode;
    }
		public Boolean getRecursively() {
    	return recursively;
    }
		public void setRecursively(Boolean recursively) {
    	this.recursively = recursively;
    }
		public Boolean getUserPermissionsChanged() {
    	return userPermissionsChanged;
    }
		public void setUserPermissionsChanged(Boolean userPermissionsChanged) {
    	this.userPermissionsChanged = userPermissionsChanged;
    }
		public Boolean getGroupPermissionsChanged() {
    	return groupPermissionsChanged;
    }
		public void setGroupPermissionsChanged(Boolean groupPermissionsChanged) {
    	this.groupPermissionsChanged = groupPermissionsChanged;
    }
		public Boolean getOtherPermissionsChanged() {
    	return otherPermissionsChanged;
    }
		public void setOtherPermissionsChanged(Boolean otherPermissionsChanged) {
    	this.otherPermissionsChanged = otherPermissionsChanged;
    }
		public String getUserPermissions() {
    	return userPermissions;
    }
		public void setUserPermissions(String userPermissions) {
    	this.userPermissions = userPermissions;
    }
		public String getGroupPermissions() {
    	return groupPermissions;
    }
		public void setGroupPermissions(String groupPermissions) {
    	this.groupPermissions = groupPermissions;
    }
		public String getOtherPermissions() {
    	return otherPermissions;
    }
		public void setOtherPermissions(String otherPermissions) {
    	this.otherPermissions = otherPermissions;
    }
	}
	
	
	private StorageBrowserView view;
	private static String NEW_PERMISSIONS_SERVER_VERSION = "6.4.0"; 
	
	public ChangePermissionsAction(StorageBrowserView view) {
		this.view = view;
		this.setText("Chanege Permissions");
	}
	
	public void run() {
		final IStructuredSelection selection = (IStructuredSelection) view.getTreeViewer().getSelection();
		Job job = new Job("Change permissions") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				try {
					List<BelowStorageNode> filesOnNewServers = new ArrayList<BelowStorageNode>();
					List<BelowStorageNode> filesOnOldServers = new ArrayList<BelowStorageNode>();
					
					for (Iterator itr = selection.iterator(); itr.hasNext();) {
						Object o = itr.next();
						if (o instanceof BelowStorageNode) {
							BelowStorageNode node = (BelowStorageNode) o;
							boolean isNew = node.getNewPermissions() != null;
							if (isNew) {
								filesOnNewServers.add(node);
							} else {
								filesOnOldServers.add(node);
							}
						}
					}
					if (monitor.isCanceled()) {
						return Status.CANCEL_STATUS;
					}
					monitor.beginTask("", filesOnNewServers.size() + filesOnOldServers.size());
					IStatus status = changePermissions(filesOnOldServers, monitor);
					if (!Status.OK_STATUS.equals(status)) {
						return Status.CANCEL_STATUS;
					}
					IStatus status2 = changePermissions2(filesOnNewServers, monitor);
					return status2;
				} finally {
					monitor.done();
				}
			}
		};
		job.schedule();
	}

	private IStatus changePermissions(List<BelowStorageNode> filesOnOldServers, IProgressMonitor monitor) {
		
		if (filesOnOldServers.isEmpty()) {
			return Status.OK_STATUS;
		}
		
		OldPermissions permissions = null;
		boolean sameValues = true;
		Boolean r = filesOnOldServers.get(0).getPermissions().getR();
		Boolean w = filesOnOldServers.get(0).getPermissions().getW();
		Boolean x = filesOnOldServers.get(0).getPermissions().getX();
		if (filesOnOldServers.size() > 1) {
			for (BelowStorageNode n : filesOnOldServers) {
				if (!r.equals(n.getPermissions().getR())) {
					sameValues = false;
					break;
				}
				if (!w.equals(n.getPermissions().getW())) {
					sameValues = false;
					break;
				}
				if (!x.equals(n.getPermissions().getX())) {
					sameValues = false;
					break;
				}
			}
		}
		if (sameValues) {
			permissions = new OldPermissions(r, w, x);
		}
		if (monitor.isCanceled()) {
			return Status.CANCEL_STATUS;
		}
		
		final OldPermissions permissions2 = permissions;
		final DialogHelper helper = new DialogHelper();
		PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
			@Override
			public void run() {
				ChangePermissionsDialog dialog = new ChangePermissionsDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), permissions2);
				dialog.open();
				helper.setReturnCode(dialog.getReturnCode());
				if (dialog.getReturnCode() == 0) {
					helper.setChanged(dialog.isChanged());
					helper.setR(dialog.getPermissions().getR());
					helper.setW(dialog.getPermissions().getW());
					helper.setX(dialog.getPermissions().getX());
				}
			}
		});
		
		
		if (helper.getReturnCode() == 0 && helper.getChanged()) {
			for (BelowStorageNode n : filesOnOldServers) {
				try {
	        n.getStorage().changePermissions(n.getPath(), helper.getR(),
	        		helper.getW(), helper.getX());
        } catch (Exception e) {
        	showErrorMessage(n);
				}
				view.getDoubleClickAction().run(n.getParent());
				monitor.worked(1);
				if (monitor.isCanceled()) {
					return Status.CANCEL_STATUS;
				}
			}
		}
		
		return Status.OK_STATUS;
	}
	

	private IStatus changePermissions2(List<BelowStorageNode> filesOnNewServers, IProgressMonitor monitor) {
		if (filesOnNewServers.isEmpty()) {
			return Status.OK_STATUS;
		}
		
		NewPermissions permissions = null;
		boolean sameValues = true;
		boolean isAnyCatalog = filesOnNewServers.get(0) instanceof CatalogNode;
		
		Boolean ur = filesOnNewServers.get(0).getNewPermissions().getUr();
		Boolean uw = filesOnNewServers.get(0).getNewPermissions().getUw();
		Boolean ux = filesOnNewServers.get(0).getNewPermissions().getUx();
		
		Boolean gr = filesOnNewServers.get(0).getNewPermissions().getGr();
		Boolean gw = filesOnNewServers.get(0).getNewPermissions().getGw();
		Boolean gx = filesOnNewServers.get(0).getNewPermissions().getGx();
		
		Boolean or = filesOnNewServers.get(0).getNewPermissions().getOr();
		Boolean ow = filesOnNewServers.get(0).getNewPermissions().getOw();
		Boolean ox = filesOnNewServers.get(0).getNewPermissions().getOx();
		
		if (filesOnNewServers.size() > 1) {
			for (BelowStorageNode n : filesOnNewServers) {
				if (n instanceof CatalogNode) isAnyCatalog = true;
				
				if (!ur.equals(n.getNewPermissions().getOr())) sameValues = false;
				if (!uw.equals(n.getNewPermissions().getOw())) sameValues = false;
				if (!ux.equals(n.getNewPermissions().getOx())) sameValues = false;
				
				if (!gr.equals(n.getNewPermissions().getGr())) sameValues = false;
				if (!gw.equals(n.getNewPermissions().getGw())) sameValues = false;
				if (!gx.equals(n.getNewPermissions().getGx())) sameValues = false;
				
				if (!or.equals(n.getNewPermissions().getOr())) sameValues = false;
				if (!ow.equals(n.getNewPermissions().getOw())) sameValues = false;
				if (!ox.equals(n.getNewPermissions().getOx())) sameValues = false;
			}
		}
		
		if (sameValues) {
			permissions = new NewPermissions(ur, uw, ux, gr, gw, gx, or, ow, ox);
		}
		if (monitor.isCanceled()) {
			return Status.CANCEL_STATUS;
		}
		final NewPermissions permissions2 = permissions;
		final Boolean isAnyCatalog2 = isAnyCatalog;
		final DialogHelper helper = new DialogHelper();
		PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
			@Override
			public void run() {
				ChangePermissions2Dialog dialog = new ChangePermissions2Dialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), permissions2, isAnyCatalog2);
				dialog.open();
				helper.setReturnCode(dialog.getReturnCode());
				if (dialog.getReturnCode() == 0) {
					helper.setMode(dialog.getMode());
					helper.setRecursively(dialog.getRecursively());
					helper.setUserPermissionsChanged(dialog.areUserPermissionsChanged());
					helper.setGroupPermissionsChanged(dialog.areUserPermissionsChanged());
					helper.setOtherPermissionsChanged(dialog.areOtherPermissionsChanged());
					helper.setUserPermissions(dialog.getUserPermissions());
					helper.setGroupPermissions(dialog.getGroupPermissions());
					helper.setOtherPermissions(dialog.getOtherPermissions());
				}
			}
		});
		if (helper.getReturnCode() == 0) {
			for (BelowStorageNode n : filesOnNewServers) {
				Enum mode = PermissionsChangeModeType.SET;
				boolean recursively = false;
				if (n instanceof CatalogNode) {
					mode = helper.getMode();
					recursively = helper.getRecursively();
				}
				boolean errorOccurred = false;
				if (helper.getUserPermissionsChanged()) {
					try {
	          n.getStorage().changePermissions2(n.getPath(), mode, PermissionsClassType.USER,
	          		helper.getUserPermissions(), recursively);
          } catch (Exception e) {
          	errorOccurred = true;
          }
				}
				if (helper.getGroupPermissionsChanged()) {
					try {
	          n.getStorage().changePermissions2(n.getPath(), mode, PermissionsClassType.GROUP,
	          		helper.getGroupPermissions(), recursively);
          } catch (Exception e) {
          	errorOccurred = true;
          }
				}
				if (helper.getOtherPermissionsChanged()) {
					try {
	          n.getStorage().changePermissions2(n.getPath(), mode, PermissionsClassType.OTHER,
	          		helper.getOtherPermissions(), recursively);
          } catch (Exception e) {
          	errorOccurred = true;
          }
				}
				view.getDoubleClickAction().run(n.getParent());
				monitor.worked(1);
				if (monitor.isCanceled()) {
					return Status.CANCEL_STATUS;
				}
				if (errorOccurred) {
					showErrorMessage(n);
				}
			}
		}
		return Status.OK_STATUS;
	}

	private void showErrorMessage(final BelowStorageNode n) {
		PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
			@Override
			public void run() {
				ILabelProvider labelProvider = new LabelProviderImplementation();
				new MessageDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error",
						null, "Error occurred after change permissions for file with name" + labelProvider.getText(n),
						MessageDialog.ERROR, new String[] {"OK"}, 0).open();
			}
		});
  }

}
